#include "stdafx.h"
#include "win_rpc.h"

#pragma comment(lib, "Rpcrt4.lib")

_SSL_BEGIN
_SSWINOSL_BEGIN

#define RPC_PROTSEQ_NAME _T("ncalrpc")

RPC_STATUS rpc_server_active(RPC_IF_HANDLE h, unsigned int min_calls, unsigned int max_calls,
	const tchar *end_point, unsigned int dnot_wait)
{
	RPC_STATUS status = RPC_S_UNKNOWN_PRINCIPAL;
	tchar *security_string = NULL;

	rpc_try
	{
		status = ::RpcServerRegisterAuthInfo(0, RPC_C_AUTHN_WINNT, 0, NULL);
		if(status != RPC_S_OK)
		{
			rpc_throw_exception(status);
		}

		status = ::RpcServerUseProtseqEp((rpc_string_type)RPC_PROTSEQ_NAME,
			RPC_C_PROTSEQ_MAX_REQS_DEFAULT, (rpc_string_type)end_point, security_string);
		if(status != RPC_S_OK)
		{
			rpc_throw_exception(status);
		}

		status = ::RpcServerRegisterIf(h, NULL, NULL);
		if(status != RPC_S_OK)
		{
			rpc_throw_exception(status);
		}

		status = ::RpcServerListen(min_calls, max_calls, dnot_wait);
		if(status != RPC_S_OK)
		{
			rpc_throw_exception(status);
		}
	}
	rpc_catch_all
	{
		status = rpc_exception_code;
	}
	rpc_end_catch;

	return status;
}

RPC_STATUS rpc_server_wait()
{
	RPC_STATUS status = RPC_S_UNKNOWN_PRINCIPAL;
	rpc_try
	{
		status = ::RpcMgmtWaitServerListen();
	}
	rpc_catch_all
	{
		status = rpc_exception_code;
	}
	rpc_end_catch;

	return status;
}

RPC_STATUS rpc_server_deactive(RPC_IF_HANDLE h)
{
	RPC_STATUS status = RPC_S_UNKNOWN_PRINCIPAL;

	rpc_try
	{
		status = ::RpcMgmtStopServerListening(NULL);
		if(status != RPC_S_OK)
		{
			rpc_throw_exception(status);
		}

		status = ::RpcServerUnregisterIf(h, NULL, NULL);
		if(status != RPC_S_OK)
		{
			rpc_throw_exception(status);
		}
	}
	rpc_catch_all
	{
		status = rpc_exception_code;
	}
	rpc_end_catch;

	return status;
}

void* rpc_client_connect(RPC_BINDING_HANDLE *h, const tchar *end_point, const tchar *net_addr)
{
	void *rpc_bind_string = NULL;
	RPC_STATUS status = RPC_S_UNKNOWN_PRINCIPAL;
	tchar *uuid = NULL, options = NULL;

	rpc_try
	{
		status = ::RpcStringBindingCompose((rpc_string_type)uuid, (rpc_string_type)RPC_PROTSEQ_NAME,
			(rpc_string_type)net_addr, (rpc_string_type)end_point, (rpc_string_type)options,
			(rpc_string_type*)&rpc_bind_string);
		if(status != RPC_S_OK)
		{
			rpc_throw_exception(status);
		}

		status = ::RpcBindingFromStringBinding((rpc_string_type)rpc_bind_string, h);
		if(status != RPC_S_OK)
		{
			rpc_throw_exception(status);
		}

		status = ::RpcBindingSetAuthInfo(*h, 0, RPC_C_AUTHN_LEVEL_NONE, RPC_C_AUTHN_WINNT, 0, 0);
		if(status != RPC_S_OK)
		{
			rpc_throw_exception(status);
		}
	}
	rpc_catch_all
	{
		status = rpc_exception_code;
	}
	rpc_end_catch;

	if(status != RPC_S_OK && rpc_bind_string != NULL)
	{
		::RpcStringFree((rpc_string_type*)&rpc_bind_string);
		rpc_bind_string = NULL;
	}

	return rpc_bind_string;
}

RPC_STATUS rpc_client_disconnect(RPC_BINDING_HANDLE *h, void *rpc_bind_string)
{
	RPC_STATUS status = RPC_S_UNKNOWN_PRINCIPAL;

	rpc_try
	{
		::RpcStringFree((rpc_string_type*)&rpc_bind_string);
		rpc_bind_string = NULL;

		status = ::RpcBindingFree(h);
	}
	rpc_catch_all
	{
		status = rpc_exception_code;
	}
	rpc_end_catch;

	return status;
}

_SSWINOSL_END
_SSL_END

